package gameeditor.mapeditor;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;

//TODO: document this class!

/**
 * The <tt>SpinnerDialog</tt> class is a {@link JDialog} extension that provides values from
 * registered {@link JSpinner} objects after a specified {@link Component}
 * generates an {@link ActionEvent}.
 * 
 * @author MetroidFan2002 (refactored into a JavaBean).
 * @author William Morrison (original author)
 * @since 1.0.2
 * @version 1.0
 * @see JDialog
 * @see ActionListener
 */
public class SpinnerDialog extends JDialog implements ActionListener {

	/**
	 * Serializable ID generated by Eclipse.
	 */
	private static final long serialVersionUID = 1L;

	protected static final JButton CANCEL_BUTTON = new JButton("Cancel");

	protected static final JButton OK_BUTTON = new JButton("Ok");

	private int inputComponentActionIndices[] = new int[] { 0 };

	private List<Component> inputComponents = new ArrayList<Component>();

	private List<JSpinner> spinners = new ArrayList<JSpinner>();

	private int spinnerValues[] = null;

	public SpinnerDialog() {
		initializeInputComponents();
		initializeSpinners();
	}

	protected void initializeSpinners() {
		getSpinners().add(new JSpinner());
		getSpinners().add(new JSpinner());
	}

	protected void initializeInputComponents() {
		OK_BUTTON.addActionListener(this);
		CANCEL_BUTTON.addActionListener(this);

		getInputComponents().add(OK_BUTTON);
		getInputComponents().add(CANCEL_BUTTON);
	}

	public SpinnerDialog(Frame owner, String description, String firstLabel,
			String secondLabel) {
		super(owner, "Input", true);

		initializeInputComponents();
		initializeSpinners();
		initializeDisplay(owner, description, firstLabel, secondLabel);
	}

	public void initializeDisplay(Frame owner, String description,
			String firstLabel, String secondLabel) {
		JPanel firstSpinnerPanel = new JPanel(new FlowLayout());
		JPanel secondSpinnerPanel = new JPanel(new FlowLayout());

		// Add spinners to JPanels.
		int stop = getSpinners().size() / 2;
		firstSpinnerPanel.add(new JLabel(firstLabel));
		for (int index = 0; index < stop; index++) {
			firstSpinnerPanel.add(getSpinners().get(index));
		}

		secondSpinnerPanel.add(new JLabel(secondLabel));
		for (int index = stop; index < getSpinners().size(); index++) {
			secondSpinnerPanel.add(getSpinners().get(index));
		}

		// Create a new JPanel for button
		JPanel inputComponentPanel = new JPanel(new FlowLayout());
		inputComponentPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5,
				5));
		for (int index = 0; index < getInputComponents().size(); index++) {
			inputComponentPanel.add(getInputComponents().get(index));
		}

		// Here is the final input panel.
		// This should be configurable via a setter.
		JPanel topPanel = new JPanel(new GridLayout(1, 2));
		add(new JLabel(description), BorderLayout.NORTH);
		topPanel.add(firstSpinnerPanel);
		topPanel.add(secondSpinnerPanel);
		add(topPanel, BorderLayout.CENTER);
		add(inputComponentPanel, BorderLayout.SOUTH);

		pack();
		setLocationRelativeTo(owner);
	}

	public void setLimits(int min, int max) {
		for (int index = 0; index < getSpinners().size(); index++) {
			getSpinners().get(index).setModel(
					createNumberModel(min, min, max, 1));
		}
	}

	protected SpinnerNumberModel createNumberModel(int v, int min, int max,
			int step) {
		return new SpinnerNumberModel(v, min, max, step);
	}

	public void actionPerformed(ActionEvent e) {
		if (isSourceSpinnerInputComponent(e.getSource())) {
			placeSpinnerValues();
		}
		dispose();
	}

	protected boolean isSourceSpinnerInputComponent(Object source) {
		if (getInputComponentActionIndices() == null) {
			return false;
		}

		int possibleIndices[] = getInputComponentActionIndices();
		int searchIndex;
		for (int index = 0; index < possibleIndices.length; index++) {
			searchIndex = possibleIndices[index];
			if (source == getInputComponents().get(searchIndex)) {
				return true;
			}
		}

		return false;
	}

	protected void placeSpinnerValues() {
		int returnedArray[] = new int[getSpinners().size()];
		for (int index = 0; index < getSpinners().size(); index++) {
			returnedArray[index] = ((Integer) getSpinners().get(index)
					.getValue()).intValue();
		}
		setSpinnerValues(returnedArray);
	}

	public static int[] getDualSpinnerDialogInput(Frame owner,
			String description, String firstLabel, String secondLabel, int min,
			int max) {
		SpinnerDialog dialog = new SpinnerDialog(owner, description,
				firstLabel, secondLabel);
		dialog.setLimits(min, max);
		dialog.setSize(200, 150);
		dialog.setLocationRelativeTo(null);
		dialog.setVisible(true);
		return dialog.getSpinnerValues();
	}

	public int[] getInputComponentActionIndices() {
		return inputComponentActionIndices;
	}

	public void setInputComponentActionIndices(int[] inputComponentActionIndices) {
		this.inputComponentActionIndices = inputComponentActionIndices;
	}

	public List<Component> getInputComponents() {
		return inputComponents;
	}

	public void setInputComponents(List<Component> inputComponents) {
		this.inputComponents = inputComponents;
	}

	public List<JSpinner> getSpinners() {
		return spinners;
	}

	public void setSpinners(List<JSpinner> spinners) {
		this.spinners = spinners;
	}

	public int[] getSpinnerValues() {
		return spinnerValues;
	}

	public void setSpinnerValues(int[] spinnerValues) {
		this.spinnerValues = spinnerValues;
	}
}
